home *** CD-ROM | disk | FTP | other *** search
- /*
-
- File: fnctdsk.c
-
- Copyright (C) 1998-2004 Christophe GRENIER <grenier@cgsecurity.org>
-
- This software is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- */
-
-
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include "types.h"
- #include "common.h"
- #include "fnctdsk.h"
- #include "lang.h"
- #include "testdisk.h"
- #include "intrface.h"
- #include "analyse.h"
-
- static void store4_little_endian(unsigned char *cp, unsigned int val)
- {
- cp[0] = (val & 0xff);
- cp[1] = ((val >> 8) & 0xff);
- cp[2] = ((val >> 16) & 0xff);
- cp[3] = ((val >> 24) & 0xff);
- }
-
- static unsigned int read4_little_endian(const unsigned char *cp)
- {
- return (unsigned int)(cp[0]) + ((unsigned int)(cp[1]) << 8) + ((unsigned int)(cp[2]) << 16) + ((unsigned int)(cp[3]) << 24);
- }
-
- unsigned int get_start_sect(const struct partition_dos *p)
- {
- return read4_little_endian(p->start4);
- }
-
- unsigned int get_nr_sects(const struct partition_dos *p)
- {
- return read4_little_endian(p->size4);
- }
-
- static void set_nr_sects(struct partition_dos *p, unsigned int nr_sects)
- {
- store4_little_endian(p->size4, nr_sects);
- }
-
- static void set_start_sect(struct partition_dos *p, unsigned int start_sect)
- {
- store4_little_endian(p->start4, start_sect);
- }
-
- dword CHS2LBA(const t_param_disk *disk_car,const t_CHS*CHS)
- { return ((dword)CHS->cylinder*(disk_car->CHS.head+1)+CHS->head)*disk_car->CHS.sector+CHS->sector-1;
- }
-
- dword C_H_S2LBA(const t_param_disk *disk_car,const word C, const byte H, const byte S)
- { return ((dword)C*(disk_car->CHS.head+1)+H)*disk_car->CHS.sector+S-1;
- }
-
- unsigned int LBA2sector(const t_param_disk *disk_car, const dword sect)
- { return (sect%disk_car->CHS.sector)+1; }
-
- unsigned int LBA2head(const t_param_disk *disk_car, const dword sect)
- { return (sect/disk_car->CHS.sector)%(disk_car->CHS.head+1); }
-
- unsigned int LBA2cylinder(const t_param_disk *disk_car, const dword sect)
- { return (sect/disk_car->CHS.sector)/(disk_car->CHS.head+1); }
-
- void LBA2CHS(const t_param_disk *disk_car,const dword lba, t_CHS*CHS)
- {
- dword pos=lba;
- CHS->sector=(pos%disk_car->CHS.sector)+1;
- pos/=disk_car->CHS.sector;
- CHS->head=pos%(disk_car->CHS.head+1);
- CHS->cylinder=pos/(disk_car->CHS.head+1);
- }
-
- void dup_t_CHS(t_CHS * CHS_dest, const t_CHS * CHS_source)
- {
- CHS_dest->cylinder=CHS_source->cylinder;
- CHS_dest->head=CHS_source->head;
- CHS_dest->sector=CHS_source->sector;
- }
-
- void dup_t_diskext(t_diskext *dest, const t_diskext *src)
- {
- dest->lba=src->lba;
- dest->boot_sector=src->boot_sector;
- dest->blocksize=src->blocksize;
- dest->part_type=src->part_type;
- dest->upart_type=src->upart_type;
- dest->part_size=src->part_size;
- dest->status=src->status;
- dest->order=src->order;
- strncpy(dest->info,src->info,sizeof(dest->info));
- strncpy(dest->name,src->name,sizeof(dest->name));
- }
-
- void partition2entry(const t_param_disk *disk_car, const dword pos, const t_diskext *partition, struct partition_dos *p)
- {
- t_CHS start,end;
- LBA2CHS(disk_car,partition->lba,&start);
- LBA2CHS(disk_car,partition->lba+partition->part_size-1,&end);
- if(partition->status==STATUS_PRIM_BOOT)
- p->boot_ind=0x80;
- else
- p->boot_ind=0; /* Non bootable */
- p->sys_ind=partition->part_type;
- set_start_sect(p,partition->lba-pos);
- if(start.cylinder>1023)
- { /* Partition Magic 5 uses CHS=(1023,0,1) if extended or last logical *
- * Linux fdisk and TestDisk use CHS=(1023,lastH,lastS) */
- p->head=(unsigned char)disk_car->CHS.head;
- p->sector=(unsigned char)(disk_car->CHS.sector|((1023>>8)<<6));
- p->cyl=(unsigned char)1023;
- }
- else
- {
- p->head=(unsigned char)start.head;
- p->sector=(unsigned char)(start.sector|((start.cylinder>>8)<<6));
- p->cyl=(unsigned char)(start.cylinder);
- }
- if(end.cylinder>1023)
- {
- p->end_head=(unsigned char)disk_car->CHS.head;
- p->end_sector=(unsigned char)(disk_car->CHS.sector|((1023>>8)<<6));
- p->end_cyl=(unsigned char)1023;
- }
- else
- {
- p->end_head=(unsigned char)end.head;
- p->end_sector=(unsigned char)(end.sector|((end.cylinder>>8)<<6));
- p->end_cyl=(unsigned char)end.cylinder;
- }
- set_nr_sects(p,partition->part_size);
- }
-
- int is_extended(const unsigned int part_type)
- {
- return (part_type==(unsigned char)P_EXTENDX || part_type==(unsigned char)P_EXTENDED || part_type==(unsigned char)P_LINUXEXTENDX);
- }
-
- int entry2partition(t_param_disk *disk_car, const dword pos, t_diskext *partition, const struct partition_dos *p, const status_type_t status,const unsigned int order,const int debug)
- {
- t_CHS start,end;
- t_CHS start_calculated,end_calculated;
- partition_reset(partition);
- partition->part_type=p->sys_ind;
- partition->lba=pos+get_start_sect(p);
- partition->order=order;
- partition->part_size=get_nr_sects(p);
-
- LBA2CHS(disk_car,partition->lba,&start_calculated);
- LBA2CHS(disk_car,partition->lba+partition->part_size-1,&end_calculated);
-
-
- start.cylinder=s_cyl(p);
- start.head=s_head(p);
- start.sector=s_sect(p);
- end.cylinder=e_cyl(p);
- end.head=e_head(p);
- end.sector=e_sect(p);
- switch(status)
- {
- case STATUS_PRIM:
- if(is_extended(partition->part_type))
- {
- partition->status=STATUS_EXT;
- partition->upart_type=UP_EXTENDED;
- }
- else
- if(p->boot_ind!=0)
- partition->status=STATUS_PRIM_BOOT;
- else
- partition->status=status;
- break;
- default:
- partition->status=status;
- break;
- }
- /* Check CHS */
- if((start.sector==0)||(start.sector>disk_car->CHS.sector))
- {
- partition->errcode=BAD_SS;
- return 1;
- }
- if((end.sector==0)||(end.sector>disk_car->CHS.sector))
- {
- partition->errcode=BAD_ES;
- return 1;
- }
- if(start.head>disk_car->CHS.head)
- {
- partition->errcode=BAD_SH;
- return 1;
- }
- if(start.cylinder>disk_car->CHS.cylinder)
- {
- partition->errcode=BAD_SC;
- return 1;
- }
- if(end.head>disk_car->CHS.head)
- {
- partition->errcode=BAD_EH;
- return 1;
- }
- if(end.cylinder>disk_car->CHS.cylinder)
- {
- partition->errcode=BAD_EC;
- return 1;
- }
- /* */
-
- if(((start_calculated.cylinder<=1023)&& (C_H_S2LBA(disk_car,start.cylinder,start.head,start.sector)!=partition->lba))
- || ((start_calculated.cylinder>1023)&&(start.cylinder!=1023)&&(start.cylinder!=(start_calculated.cylinder&1023))))
- {
- ecrit_rapport("BAD_RS LBA=%ld %ld\n",partition->lba,C_H_S2LBA(disk_car,start.cylinder,start.head,start.sector));
- partition->errcode=BAD_RS;
- return 1;
- }
-
- if(((end_calculated.cylinder<=1023)&& (C_H_S2LBA(disk_car,end.cylinder,end.head,end.sector)!=partition->lba+partition->part_size-1))
- || ((end_calculated.cylinder>1023)&&(end.cylinder!=1023)&&(end.cylinder!=(end_calculated.cylinder&1023))))
- {
- partition->errcode=BAD_SCOUNT;
- return 1;
- }
- /* Check partition and load partition name */
- check_part(disk_car,debug,partition);
- return 0;
- }
-
- const char* errmsg_entry2partition(const errcode_type_t errcode)
- {
- switch(errcode)
- {
- case BAD_SS: return msg_BAD_S_SECT;
- case BAD_ES: return msg_BAD_E_SECT;
- case BAD_SH: return msg_BAD_S_HEAD;
- case BAD_EH: return msg_BAD_E_HEAD;
- case BAD_EBS: return msg_END_BFR_START;
- case BAD_RS: return msg_BAD_RS;
- case BAD_SC: return msg_BAD_S_CYL;
- case BAD_EC: return msg_BAD_E_CYL;
- case BAD_SCOUNT: return msg_BAD_SCOUNT;
- case BAD_NOERR: return "";
- }
- ecrit_rapport("errmsg_entry2partition: unhandled error\n");
- return "";
- }
-
- int read_MBR(t_param_disk *disk_car,void *buffer)
- {
- if(disk_car->read(disk_car,1, buffer, 0))
- {
- wdoprintf(stdscr,msg_PART_RD_ERR);
- return 1;
- }
- return 0;
- }
-
- int write_MBR(t_param_disk *disk_car,void *buffer)
- {
- if(disk_car->write(disk_car,1, buffer, 0))
- {
- wdoprintf(stdscr,msg_PART_WR_ERR);
- return 1;
- }
- return 0;
- }
-
- t_list_disk *insert_new_disk(t_list_disk *list_disk, t_param_disk *disk_car)
- {
- if(disk_car==NULL)
- return list_disk;
- {
- t_list_disk *prev;
- t_list_disk *new_disk=(t_list_disk *)MALLOC(sizeof(*new_disk));
- new_disk->disk=disk_car;
- /* Add it at the end */
- for(prev=list_disk;prev && prev->next;prev=prev->next);
- if(prev!=NULL)
- {
- prev->next=new_disk;
- }
- new_disk->prev=prev;
- new_disk->next=NULL;
- return (list_disk!=NULL?list_disk:new_disk);
- }
- }
-
- t_list_part *insert_new_partition(t_list_part *list_part, t_diskext *part)
- {
- return insert_new_partition_aux(list_part, element_new(part));
- }
-
- t_list_part *insert_new_partition_aux(t_list_part *list_part, t_list_part *new_element)
- { /* new partition musn't be used after insert !*/
- t_list_part *prev=NULL;
- t_list_part *next;
- for(next=list_part;;next=next->next)
- { /* prev new next */
- if((next==NULL)||(new_element->part->lba<next->part->lba)||((new_element->part->lba==next->part->lba)&&(new_element->part->part_size<=next->part->part_size)))
- {
- if((next!=NULL)&&(next->part->lba==new_element->part->lba)&&(next->part->part_size==new_element->part->part_size)&&(next->part->part_type==new_element->part->part_type)&&(next->part->upart_type==new_element->part->upart_type))
- {
- FREE(new_element->part);
- FREE(new_element);
- return list_part;
- }
- else
- { /* prev new_element next */
- new_element->next=next;
- new_element->prev=prev;
- if(next!=NULL)
- next->prev=new_element;
- if(prev!=NULL)
- {
- prev->next=new_element;
- return list_part;
- }
- return new_element;
- }
- }
- prev=next;
- }
- ecrit_rapport("insert_new_partition_aux : BUG!\n");
- exit(EXIT_FAILURE);
- }
-
- int check_list_part(t_list_part *list_part)
- {
- t_list_part *prev=NULL;
- t_list_part *parts;
- if((list_part!=NULL) && (list_part->prev!=NULL))
- {
- ecrit_rapport("\ncheck_list_part error: list_part->prev!=NULL\n");
- exit(EXIT_FAILURE);
- }
- for(parts=list_part;parts!=NULL;parts=parts->next)
- {
- /*ecrit_rapport("%p %p %p\n",parts->prev, parts, parts->next); */
- if(prev!=parts->prev)
- {
- ecrit_rapport("\ncheck_list_part error: prev!=parts->prev\n");
- exit(EXIT_FAILURE);
- }
- prev=parts;
- }
- if((prev!=NULL) && (prev->next!=NULL))
- {
- ecrit_rapport("\ncheck_list_part error: prev->next!=NULL\n");
- exit(EXIT_FAILURE);
- }
- return 0;
- }
-
- t_list_part *sort_list_part(t_list_part *list_part)
- {
- t_list_part *new_list_part=NULL;
- t_list_part *element;
- t_list_part *next;
- for(element=list_part;element!=NULL;element=next)
- {
- next=element->next;
- new_list_part=insert_new_partition_aux(new_list_part,element);
- }
- return new_list_part;
- }
-
- void delete_list_part(t_list_part *list_part)
- {
- t_list_part *element;
- /* Libere la memoire */
- element=list_part;
- while(element!=NULL)
- {
- t_list_part *next=element->next;
- FREE(element->part);
- FREE(element);
- element=next;
- }
- }
-
- void partition_reset(t_diskext *partition)
- {
- /* partition->lba=0; Don't reset lba, used by search_part */
- partition->part_size=0;
- partition->boot_sector=0;
- partition->blocksize=0;
- partition->part_type=P_NO_OS;
- partition->upart_type=UP_UNK;
- partition->status=STATUS_DELETED;
- partition->order=0;
- partition->errcode=BAD_NOERR;
- partition->name[0]='\0';
- partition->info[0]='\0';
- }
-
- t_diskext *partition_new()
- {
- t_diskext *partition=(t_diskext *)MALLOC(sizeof(*partition));
- partition_reset(partition);
- return partition;
- }
-
- t_list_part *element_new(t_diskext *part)
- {
- t_list_part *new_element=(t_list_part*)MALLOC(sizeof(*new_element));
- new_element->part=part;
- new_element->prev=new_element->next=NULL;
- new_element->to_be_removed=0;
- return new_element;
- }
-
- int can_be_ext(const t_param_disk *disk_car, t_diskext *partition)
- {
- return((LBA2head(disk_car,partition->lba)>0)&&
- (LBA2cylinder(disk_car,partition->lba)!=0 ||
- LBA2head(disk_car,partition->lba)!=1 ||
- LBA2sector(disk_car,partition->lba)!=1));
- }
-
- int test_structure(t_list_part *list_part)
- { /* Return 1 if bad*/
- int nbr_prim=0, nbr_prim_boot=0, nbr_log_block=0;
- t_list_part *first_log=NULL;
- t_list_part *new_list_part=NULL;
- t_list_part *element;
- t_list_part *new_element;
- int res=0;
- for(element=list_part;element!=NULL;element=element->next)
- {
- switch(element->part->status)
- {
- case STATUS_LOG:
- if(first_log==NULL)
- {
- first_log=element;
- nbr_log_block++;
- }
- if(is_extended(element->part->part_type))
- return 1;
- break;
- case STATUS_PRIM_BOOT:
- if(nbr_prim_boot++)
- return 1;
- case STATUS_PRIM:
- nbr_prim++;
- first_log=NULL;
- break;
- case STATUS_DELETED:
- break;
- default:
- ecrit_rapport("test_structure: severe error\n");
- break;
- }
- }
- if(nbr_log_block>1 || nbr_log_block+nbr_prim>4)
- return 1;
- /* Sort list_part in new_list_part */
- for(element=list_part;element!=NULL;element=element->next)
- {
- if(element->part->status!=STATUS_DELETED)
- new_list_part=insert_new_partition(new_list_part,element->part);
- }
- /* Test chevauchement */
- /* ecrit_rapport("\nTest chevauchement\n"); */
- for(element=new_list_part;element!=NULL;element=element->next)
- {
- /* ecrit_rapport("start %lu, end %lu\n", element->part->lba,element->part->lba+element->part->part_size-1); */
- if(((element->prev!=NULL) && (element->part->lba<=element->prev->part->lba+element->prev->part->part_size-1)) ||
- ((element->next!=NULL) && (element->part->lba+element->part->part_size-1>=element->next->part->lba)))
- {
- /* ecrit_rapport("\nChevauchement\n"); */
- res=1;
- }
- }
- /* ecrit_rapport("Test chevauchement fin\n"); */
- for(element=new_list_part;element!=NULL;element=new_element)
- {
- new_element=element->next;
- FREE(element);
- }
- return res;
- }
-
-